package com.lifang.imsoa.facadeimpl;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.lifang.imsoa.dao.miles.read.HxUserReadMapper;
import com.lifang.imsoa.dao.miles.write.HxAppExtMsgWriteMapper;
import com.lifang.imsoa.dao.miles.write.HxUserWriteMapper;
import com.lifang.imsoa.entity.ErrorResponse;
import com.lifang.imsoa.entity.miles.HxAppExtMsg;
import com.lifang.imsoa.entity.miles.HxUser;
import com.lifang.imsoa.facade.ImUserFacadeService;
import com.lifang.imsoa.im.apidemo.EasemobIMUsers;
import com.lifang.imsoa.im.comm.Constants;
import com.lifang.imsoa.im.comm.HTTPMethod;
import com.lifang.imsoa.im.service.MessageServiceImpl;
import com.lifang.imsoa.im.utils.JerseyUtils;
import com.lifang.imsoa.im.vo.Credential;
import com.lifang.imsoa.im.vo.EndPoints;
import com.lifang.imsoa.model.Entity;
import com.lifang.imsoa.model.HxUserOnlineStatus;
import com.lifang.imsoa.model.UserBaseResponse;
import com.lifang.imsoa.model.UserOnlineStatusResponse;
import com.lifang.imsoa.model.request.AppNameEnum;
import com.lifang.imsoa.model.request.AppSendMsgRequest;
import com.lifang.imsoa.model.request.ImUserRequest;
import com.lifang.imsoa.model.request.SendMessageRequest;
import com.lifang.imsoa.model.response.BusinessException;
import com.lifang.imsoa.model.response.ErrorEnum;
import com.lifang.imsoa.model.response.HxUserEntity;
import com.lifang.imsoa.model.response.HxUserStatus;
import com.lifang.imsoa.util.*;
import com.lifang.json.FasterJsonTool;
import com.lifang.model.Response;
import com.lifang.xmemcached.RedisClientAdapterImpl;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.glassfish.jersey.client.JerseyWebTarget;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Slf4j
@Service
public class ImUserFacadeServiceImpl implements ImUserFacadeService {
	@Autowired
	private RedisClientAdapterImpl redisClientAdapter;
	@Autowired
	private HxAppExtMsgWriteMapper hxAppExtMsgWriteMapper;
	
	//缓存时间
	@Value("${I_cacheTime}")
	private int cacheTime;

	@Autowired
	private ClearRedis clearRedis;

	@Autowired
	private MessageServiceImpl messageServiceImpl;

	@Autowired
	private ThreadPoolTaskExecutor threadPoolTaskExecutor;
	@Autowired
	private HxUserReadMapper hxUserReadMapper;
	@Autowired
	private HxUserWriteMapper hxUserWriteMapper;

	private static JsonNodeFactory factory = new JsonNodeFactory(false);
	private static String JRSP_APPKEY = Constants.JRSP_APPKEY;

	// 通过app的client_id和client_secret来获取app管理员token
    private static Credential jrsp_credential = Constants.jrsp_credential;

    private static Long PerNumber = 50L;//批量注册用户时，单次提交的个数

	private static String HXID_EXIST_FLAG = "1";
	/**
     * 注册IM用户[单个]
     */
    @Override
	public UserBaseResponse xCreateNewIMUserSingle(ImUserRequest imUserRequest){
    	ObjectNode createNewIMUserSingleNode= commonRegSingle(imUserRequest, JRSP_APPKEY, jrsp_credential);
	    Response<UserBaseResponse> r = getResult(createNewIMUserSingleNode, UserBaseResponse.class);
		clearRedis.clearRedisByHxId(r.getData().getEntities().get(0).getUsername());
	    return r.getData();
	}

    /**
     * 获取IM用户[主键查询]
     */
    public Response<UserBaseResponse> xGetIMUsersByPrimaryKey(String userName){
    	if(!ValidateUtil.checkUsername(userName)){
    		log.info("用户名非法,userName={}",userName);
	    	throw new RuntimeException(ErrorEnum.SOA_ERROR_200001.getMessage());
	    }
	    ObjectNode getIMUsersByPrimaryKeyNode = getIMUsersByPrimaryKey(userName);
	    if (null != getIMUsersByPrimaryKeyNode) {
	        log.info("获取IM用户[主键查询]: " + getIMUsersByPrimaryKeyNode.toString());
	    }
	    return getResult(getIMUsersByPrimaryKeyNode, UserBaseResponse.class);
    }

    /**
	 * 注册IM用户[单个]
	 * 
	 * 给指定AppKey创建一个新的用户
	 * 
	 * @param dataNode
	 * @return
	 */
	public static ObjectNode createNewIMUserSingle(ObjectNode dataNode,String appkey,Credential credential) {
		ObjectNode objectNode = factory.objectNode();
		// check appKey format
		if (!JerseyUtils.match("^(?!-)[0-9a-zA-Z\\-]+#[0-9a-zA-Z]+", appkey)) {
			log.error("Bad format of Appkey: " + appkey);
			objectNode.put("message", "Bad format of Appkey");
			return objectNode;
		}
		objectNode.removeAll();
		// check properties that must be provided
		if (null != dataNode && !dataNode.has("username")) {
			log.error("环信ID必须提供");
			objectNode.put("message","环信ID必须提供");
			return objectNode;
		}
		if (null != dataNode && !dataNode.has("password")) {
			log.error("密码必须提供");
			objectNode.put("message","密码必须提供");
			return objectNode;
		}
		JerseyWebTarget webTarget = null;
		try {
			webTarget = EndPoints.USERS_TARGET.resolveTemplate("org_name",
					appkey.split("#")[0]).resolveTemplate("app_name",appkey.split("#")[1]);
			objectNode = JerseyUtils.sendRequest(webTarget, dataNode, credential, HTTPMethod.METHOD_POST, null);
		} catch (Exception e) {
			log.info("注册单个用户时sendRequest方法抛出异常,webTarget={},dataNode={},hxId={}",
					webTarget,dataNode, dataNode != null ? dataNode.get("username") : null);
			e.printStackTrace();
		}
		return objectNode;
	}

	/**
	 * 注册IM用户[批量生成用户然后注册]
	 * 
	 * 给指定AppKey创建一批用户
	 * 
	 * @param perNumber
	 *            批量注册时一次注册的数量
	 * @return
	 */
	public static ObjectNode createNewIMUserBatchGen(List<String> userIds,
			Long perNumber,String appkey,Credential credential,String prexUserName) {
		ObjectNode objectNode = factory.objectNode();
		Long totalNumber = (long)userIds.size();
		if (totalNumber == 0 || perNumber == 0) {
			return objectNode;
		}
		ArrayNode genericArrayNode = genericArrayNode(userIds,prexUserName);
		if (totalNumber <= perNumber) {
			objectNode = EasemobIMUsers.createNewIMUserBatch(genericArrayNode, appkey,credential);
		} else {
			for (int i = 0; i < genericArrayNode.size(); i++) {
				ArrayNode tmpArrayNode = factory.arrayNode();
				tmpArrayNode.add(genericArrayNode.get(i));
				// 300 records on one migration
				if ((i + 1) % perNumber == 0) {
					objectNode = EasemobIMUsers
							.createNewIMUserBatch(genericArrayNode,appkey,credential);
					tmpArrayNode.removeAll();
					continue;
				}
				// the rest records that less than the times of 300
				if (i > (genericArrayNode.size() / perNumber * perNumber - 1)) {
					objectNode = EasemobIMUsers
							.createNewIMUserBatch(genericArrayNode,appkey,credential);
					tmpArrayNode.removeAll();
				}
			}
		}
		return objectNode;
	}

	/**
	 * 获取IM用户
	 * 
	 * @param userPrimaryKey
	 *            用户主键：username或者uuid
	 * @return
	 */
	public static ObjectNode getIMUsersByPrimaryKey(String userPrimaryKey) {
		ObjectNode objectNode = factory.objectNode();

		// check appKey format
		if (!JerseyUtils.match("^(?!-)[0-9a-zA-Z\\-]+#[0-9a-zA-Z]+", JRSP_APPKEY)) {
			log.error("Bad format of Appkey: " + JRSP_APPKEY);

			objectNode.put("message", "Bad format of Appkey");

			return objectNode;
		}

		// check properties that must be provided
		if (StringUtils.isEmpty(userPrimaryKey)) {
			log.error("The primaryKey that will be useed to query must be provided .");

			objectNode
					.put("message",
							"The primaryKey that will be useed to query must be provided .");

			return objectNode;
		}

		try {

			JerseyWebTarget webTarget = null;
			webTarget = EndPoints.USERS_TARGET
					.resolveTemplate("org_name", JRSP_APPKEY.split("#")[0])
					.resolveTemplate("app_name", JRSP_APPKEY.split("#")[1])
					.path(userPrimaryKey);

			objectNode = JerseyUtils.sendRequest(webTarget, null, jrsp_credential,
					HTTPMethod.METHOD_GET, null);

		} catch (Exception e) {
			e.printStackTrace();
		}

		return objectNode;
	}

	/**
	 * 删除IM用户[单个]
	 * 
	 * 删除指定AppKey下IM单个用户
	 *
	 * 
	 * @param userPrimaryKey
	 * @return
	 */
	public static ObjectNode deleteIMUserByUserPrimaryKey(String userPrimaryKey,String appkey,Credential credential) {
		ObjectNode objectNode = factory.objectNode();

		// check appKey format
		if (!JerseyUtils.match("^(?!-)[0-9a-zA-Z\\-]+#[0-9a-zA-Z]+", appkey)) {
			log.error("Bad format of Appkey: " + appkey);
			objectNode.put("message", "Bad format of Appkey");
			return objectNode;
		}

		try {
			JerseyWebTarget webTarget = null;
			webTarget = EndPoints.USERS_TARGET
					.resolveTemplate("org_name", appkey.split("#")[0])
					.resolveTemplate("app_name", appkey.split("#")[1])
					.path(userPrimaryKey);

			objectNode = JerseyUtils.sendRequest(webTarget, null, credential,
					HTTPMethod.METHOD_DELETE, null);

		} catch (Exception e) {
			e.printStackTrace();
		}

		return objectNode;
	}

	private static ArrayNode genericArrayNode(List<String> userIds,String prexUserName) {
		ArrayNode arrayNode = factory.arrayNode();
		for (String userId:userIds) {
			if(StringUtils.isBlank(userId)){
				throw new RuntimeException("集合中存在为空的用户ID");
			}
			ObjectNode userNode = factory.objectNode();
			String userName = prexUserName + userId;
			if(!ValidateUtil.checkUsername(userName)){
		    	throw new RuntimeException(ErrorEnum.SOA_ERROR_200001.getMessage());
		    }
			userNode.put("username", userName);
			userNode.put("password", Global.DEFAULT_PASSWORD);
			arrayNode.add(userNode);
		}
		return arrayNode;
	}

	@Override
	public Response<HxUserEntity> xCreateNewIMUserSingleForSys(String userId,AppNameEnum appNameEnum) {
		if(StringUtils.isBlank(userId)){
			log.info("用户ID为空,userId={},system={}",userId,appNameEnum.getAppName());
			throw new BusinessException(ErrorEnum.SOA_ERROR_200004);
		}
		String hxId;
		if(appNameEnum==null){
			log.info("系统类型为空,userId={}",userId);
			throw new BusinessException(ErrorEnum.SOA_ERROR_200005);
		}else{
			hxId = appNameEnum.getAppName() + userId;
		}
		regUser(Arrays.asList(userId),appNameEnum);
		HxUserEntity hxUserEntity = new HxUserEntity();
		hxUserEntity.setHxId(hxId);
		hxUserEntity.setPassword(Global.DEFAULT_PASSWORD);
		return ResponseUtil.getResultToResponse(hxUserEntity);
		
	}

	private ObjectNode commonRegSingle(ImUserRequest imUserRequest,String appkey,Credential credential){
		ObjectNode datanode = JsonNodeFactory.instance.objectNode();
	    //[a-zA-Z0-9_-.]*
	    if(!ValidateUtil.checkUsername(imUserRequest.getUserName())){
	    	throw new BusinessException(ErrorEnum.SOA_ERROR_200001);
	    }
	    imUserRequest.setPassword(Global.DEFAULT_PASSWORD);
	    datanode.put("username", imUserRequest.getUserName());
	    datanode.put("password", imUserRequest.getPassword());
	    datanode.put("nickname", imUserRequest.getNickName());
		return createNewIMUserSingle(datanode,appkey,credential);
	}

	@Override
	public Response<List<HxUserEntity>> xCreateNewIMUserBatchGen(List<String> userIds,AppNameEnum appNameEnum) {
		if(CollectionUtils.isEmpty(userIds)){
			log.info("批量注册环信用户,传入的用户ID为空,userIds={}",userIds);
			return ResponseUtil.getResultToResponse(new ArrayList<>());
		}
		String appkey;
		Credential credential;
		if(appNameEnum==null){
			log.info("系统类型为空,imUsers'size={}",userIds.size());
			throw new BusinessException(ErrorEnum.SOA_ERROR_200009);
		}else{
			appkey = JRSP_APPKEY;
			credential = jrsp_credential;
		}
		ObjectNode objectNode = createNewIMUserBatchGen(userIds, PerNumber,appkey,credential,appNameEnum.getAppName());
	    if (null != objectNode) {
	        log.info("注册IM用户[批量]={}",objectNode.toString());
			if(200==objectNode.get("statusCode").asInt()){
				UserBaseResponse userBaseResponse = FasterJsonTool.readValue(objectNode.toString(), UserBaseResponse.class);
				List<Entity> entities = userBaseResponse.getEntities();//环信返回的数据
				List<HxUserEntity> hxUsers = new ArrayList<>();//返回给调用方的数据
				List<String> hxIds = new ArrayList<>();//存放注册成功的环信ID,用于刷新缓存
				for(Entity entity:entities){
					hxIds.add(entity.getUsername());
					HxUserEntity hxUser = new HxUserEntity();
					hxUser.setHxId(entity.getUsername());
					hxUser.setPassword(Global.DEFAULT_PASSWORD);
					hxUsers.add(hxUser);
					insertUserToCacheAndDB(hxUser.getHxId().substring(4),appNameEnum);
				}
				return ResponseUtil.getResultToResponse(hxUsers);
			}else{
				log.info("调用环信接口失败,objectNode={}",objectNode);
				ErrorResponse errorResponse = FasterJsonTool.readValue(objectNode.toString(), ErrorResponse.class);
				HXErrorCodeEnum errorEnum = HXErrorCodeEnum.getErrorEnumByStatus(errorResponse);
				if(errorEnum!=null){
					throw new BusinessException(errorEnum.getResponseNo(), errorEnum.getMessage());
				}else{
					log.info("非正常情况,error={}",objectNode.toString());
					throw new BusinessException(-1, "服务器内部错误");
				}
			}
		}else{
			//此种情况是需要关注的特别异常的情况
			log.info("注册用户异常,objectNode=null,请查询是否注册成功,userIds={},system={}",
					userIds,appNameEnum.getAppName());
			throw new BusinessException(ErrorEnum.SOA_ERROR_200010);
		}
	}

	@Override
	public Response<?> xDeleteIMUserByUserPrimaryKey(String userId, AppNameEnum appNameEnum) {
		String appkey;
		Credential credential;
		String hxId;
		if(StringUtils.isBlank(userId)){
			log.info("用户ID为空,userId={}",userId);
			throw new RuntimeException("用户ID不能为空");
		}
		if(appNameEnum==null){
			log.info("系统类型为空,userId={}",userId);
			throw new RuntimeException("系统类型为空");
		}else{
			appkey = JRSP_APPKEY;
			credential = jrsp_credential;
			hxId = appNameEnum.getAppName()+userId;
		}
		ObjectNode objectNode = deleteIMUserByUserPrimaryKey(hxId,appkey,credential);
	    if (null != objectNode) {
	        log.info("删除IM用户[单个]: " + objectNode.toString());
	    }
		deleteFromCacheAndDB(userId,appNameEnum);
    	if(200==objectNode.get("statusCode").asInt()){
	    	return ResponseUtil.getResultToResponse(null);
	    }else{
	    	log.info("调用环信接口失败,error={}",objectNode);
	    	ErrorResponse errorResponse = FasterJsonTool.readValue(objectNode.toString(), ErrorResponse.class);
	    	HXErrorCodeEnum errorEnum = HXErrorCodeEnum.getErrorEnumByStatus(errorResponse);
	    	if(errorEnum!=null){
	    		throw new BusinessException(errorEnum.getResponseNo(), errorEnum.getMessage());
	    	}else{
	    		log.info("非正常情况,error={}",objectNode.toString());
	    		throw new BusinessException(-1, "服务器内部错误");
	    	}
	    }
	}

	@Override
	public Response<?> sendMsg(SendMessageRequest sendMessageRequest) {
        if(StringUtils.isBlank(sendMessageRequest.getFromHxId())){
            sendMessageRequest.setFromHxId("admin");
        }
		log.info("发消息开始,msg={},ext={}",sendMessageRequest.getMsg(),sendMessageRequest.getExt());
		ObjectNode objectNode = messageServiceImpl.sendMsg(sendMessageRequest);
		if(200==objectNode.get("statusCode").asInt()){
			log.info("调用环信发消息接口成功");
			return ResponseUtil.getResultToResponse(null);
		}else{
			log.info("调用环信发消息接口失败");
			throw new BusinessException(ErrorEnum.SOA_ERROR_200003);
		}
	}
	
	public static <T> Response<T> getResult(ObjectNode objectNode,Class<T> c){
    	Response<T> result = new Response<T>();
    	if(200==objectNode.get("statusCode").asInt()){
    		result.setStatus(1);
    		result.setMessage("成功");
    		result.setData(FasterJsonTool.readValue(objectNode.toString(), c));
	    	return result;
	    }else{
	    	log.info("调用环信接口失败,error={}",objectNode);
	    	ErrorResponse errorResponse = FasterJsonTool.readValue(objectNode.toString(), ErrorResponse.class);
	    	HXErrorCodeEnum errorEnum = HXErrorCodeEnum.getErrorEnumByStatus(errorResponse);
	    	if(errorEnum!=null){
	    		throw new BusinessException(errorEnum.getResponseNo(), errorEnum.getMessage());
	    	}else{
	    		log.info("非正常情况,error={}",objectNode.toString());
	    		throw new BusinessException(-1, "服务器内部错误");
	    	}
	    }
    }

	@Override
	public Response<List<HxUserStatus>> getUserIdByHxId(List<String> hxIds, AppNameEnum appNameEnum) {
		List<HxUserStatus> hxUserStatuses = new ArrayList<>();
		if(CollectionUtils.isNotEmpty(hxIds)){
			log.info("===>根据环信ID获得用户ID,hxIds={}",hxIds);
			List<String> userIds = new ArrayList<>();
			for(String hxId:hxIds){
				if("admin".equals(hxId)){
					userIds.add("-1");
				}else {
					userIds.add(hxId.substring(4));
				}
			}
			getHxIdAndUserId(userIds, appNameEnum, hxUserStatuses);
			log.info("<===根据环信ID获得用户ID调用完成");
		}
		return ResponseUtil.getResultToResponse(hxUserStatuses);
	}

	@Override
	public Response<List<HxUserStatus>> getHxIdByUserId(List<String> userIds, AppNameEnum appNameEnum) {
		List<HxUserStatus> hxUserStatuses = new ArrayList<HxUserStatus>();
		if(CollectionUtils.isNotEmpty(userIds)){
			log.info("===>根据用户ID获得环信ID,userIds={},system={}",userIds,appNameEnum.getAppName());
			getHxIdAndUserId(userIds, appNameEnum, hxUserStatuses);
			log.info("<===根据用户ID获得环信ID调用完成");
		}
		return ResponseUtil.getResultToResponse(hxUserStatuses);
	}

	@Override
	public Response<HxUserOnlineStatus> selectHxUserIsOnline(String userId, AppNameEnum system) {
		HxUserOnlineStatus hxUserOnlineStatus = new HxUserOnlineStatus();
		if(StringUtils.isBlank(userId)){
			throw new BusinessException(ErrorEnum.SOA_ERROR_200004);
		}else if("-1".equals(userId)){
			hxUserOnlineStatus.setUserId("-1");
			hxUserOnlineStatus.setHxId("admin");
			hxUserOnlineStatus.setOnlineStatus(1);
		}else {
			String hxId = system.getAppName() + userId;
			hxUserOnlineStatus.setHxId(hxId);
			hxUserOnlineStatus.setUserId(userId);
			log.info("查询用户是否在线,hxId={}", hxId);
			ObjectNode objectNode = EasemobIMUsers.selectHxUserOnlineStatus(hxId, JRSP_APPKEY, jrsp_credential);
			if (objectNode != null && objectNode.get("statusCode") != null) {
				if (200 == objectNode.get("statusCode").asInt()) {
					log.info("查询用户是否在线成功,{}", hxId);
					UserOnlineStatusResponse errorResponse = FasterJsonTool.readValue(objectNode.toString(), UserOnlineStatusResponse.class);
					if ("online".equals(errorResponse.getData().get(hxId))) {
						hxUserOnlineStatus.setOnlineStatus(1);
					} else {
						hxUserOnlineStatus.setOnlineStatus(2);
					}
					log.info("查询用户是否在线hxId={},onlinestatus={}",hxId,errorResponse.getData().get(hxId));
				} else {
					ErrorResponse errorResponse = FasterJsonTool.readValue(objectNode.toString(), ErrorResponse.class);
					HXErrorCodeEnum errorEnum = HXErrorCodeEnum.getErrorEnumByStatus(errorResponse);
					if (errorEnum != null) {
						log.info("查询用户在线状态出错,errorEnum={}", errorEnum.getMessage());
					} else {
						log.info("查询用户在线状态非正常情况,环信返回objectNode={}", objectNode.toString());
					}
					hxUserOnlineStatus.setOnlineStatus(2);
				}
			}else{
				log.info("objectNode.get(\"statusCode\")={}",objectNode.get("statusCode"));
				hxUserOnlineStatus.setOnlineStatus(2);
			}
		}
		return ResponseUtil.getResultToResponse(hxUserOnlineStatus);
	}

	private void getHxIdAndUserId(List<String> userIds, AppNameEnum appNameEnum, List<HxUserStatus> hxUserStatuses) {
		String appName = appNameEnum.getAppName();
		Integer system = appNameEnum.getSystem();
		List<String> noCacheUserIds = new ArrayList<>();//保存没有缓存的用户ID
		for (String userId : userIds) {
            HxUserStatus hxUserStatus = new HxUserStatus();
            hxUserStatus.setUserId(userId);
            hxUserStatus.setStatus(1);
            hxUserStatus.setPassword(Global.DEFAULT_PASSWORD);
            if("-1".equals(userId)){
                hxUserStatus.setHxId("admin");
            }else{
                String hxId = appName+userId;
                hxUserStatus.setHxId(hxId);

                //1.查询缓存,任务放在主线程中
                Object cacheObj = redisClientAdapter.get(RedisKey.hxUserStatus.key(hxId));
                if(cacheObj==null || !HXID_EXIST_FLAG.equals(cacheObj.toString())){
                    noCacheUserIds.add(userId);
                }
            }
            hxUserStatuses.add(hxUserStatus);
        }
		log.info("需要查询数据库的用户id,userIds={}",noCacheUserIds);
		//2.查数据库
		if(noCacheUserIds.size()>0) {
            Map<String, Object> param = new HashMap<>();
            param.put("userIds", noCacheUserIds);
            param.put("system", system);
            List<String> existUserIds = hxUserReadMapper.selectByUserIdAndSystem(param);
			log.info("数据库已经有的用户={}",existUserIds);
            if (CollectionUtils.isNotEmpty(existUserIds)) {
                for (String existUserId : existUserIds) {
                    redisClientAdapter.set(RedisKey.hxUserStatus.key(appName+existUserId), HXID_EXIST_FLAG, cacheTime);
                }
                noCacheUserIds.removeAll(existUserIds);//得到没有注册的用户
            }
        }
		//3.将注册用户的任务委托给线程池
		log.info("需要调用环信注册接口的用户id,userIds={}",noCacheUserIds);
		if(noCacheUserIds.size()>0) {
            regUser(noCacheUserIds, appNameEnum);
        }
	}

	public void regUser(final List<String> userIds, final AppNameEnum appName) {
		threadPoolTaskExecutor.execute(new Runnable() {
			@Override
			public void run() {
				for(String userId:userIds) {
					regUserByRestAPI(userId,appName);
				}
			}
		});
	}

	private void regUserByRestAPI(String userId,AppNameEnum appName) {
		String hxId = appName.getAppName()+userId;
		ImUserRequest imUserRequest = new ImUserRequest();
		imUserRequest.setUserName(hxId);
		ObjectNode objectNode = commonRegSingle(imUserRequest, JRSP_APPKEY, jrsp_credential);
		if(objectNode!=null && objectNode.get("statusCode")!=null) {
			if (200 == objectNode.get("statusCode").asInt()) {
				log.info("第一次注册成功,hxId={}",hxId);
			} else {
				ErrorResponse errorResponse = FasterJsonTool.readValue(objectNode.toString(), ErrorResponse.class);
				HXErrorCodeEnum errorEnum = HXErrorCodeEnum.getErrorEnumByStatus(errorResponse);
				if (errorEnum != null) {
					log.info("第一次调用环信接口返回状态异常,errorEnum={}", errorEnum);
				} else {
					log.info("第一次非正常情况,环信返回objectNode={}", objectNode.toString());
				}
			}
			insertUserToCacheAndDB(userId, appName);
		}else{
			log.info("尝试第二次注册,hxId={}",hxId);
			//再尝试注册一次
			ObjectNode objectNodeAgain = commonRegSingle(imUserRequest, JRSP_APPKEY, jrsp_credential);
			log.info("第二次注册结束,hxId={}",hxId);
			if(objectNodeAgain!=null && objectNodeAgain.get("statusCode")!=null) {
				if (200 == objectNodeAgain.get("statusCode").asInt()) {
					log.info("第二次注册成功,hxId={}",hxId);
				}else{
					ErrorResponse errorResponse = FasterJsonTool.readValue(objectNodeAgain.toString(), ErrorResponse.class);
					HXErrorCodeEnum errorEnum = HXErrorCodeEnum.getErrorEnumByStatus(errorResponse);
					if (errorEnum != null) {
						log.info("第二次调用环信接口返回状态异常,errorEnum={}", errorEnum);
					} else {
						log.info("第二次非正常情况,环信返回objectNode={}", objectNodeAgain.toString());
					}
				}
				insertUserToCacheAndDB(userId, appName);//第二次放宽写入缓存和数据库的条件
			}else{
				log.info("第二次注册用户终极异常,objectNode={},请查询是否注册成功,hxId={}",
						objectNodeAgain != null ? objectNodeAgain.toString() : null,hxId);
			}
		}
	}

	@Transactional
	public void insertUserToCacheAndDB(String userId, AppNameEnum appName) {
		String hxId = appName.getAppName()+userId;
		//写入缓存
		redisClientAdapter.set(RedisKey.hxUserStatus.key(hxId), HXID_EXIST_FLAG, cacheTime);
		//写入数据库
		HxUser hxUser = new HxUser();
		hxUser.setUserId(Integer.parseInt(userId));
		hxUser.setHxId(hxId);
		hxUser.setStatus((byte)1);
		hxUser.setSystem(appName.getSystem().byteValue());
		try{
			hxUserWriteMapper.insertSelective(hxUser);
		}catch(Exception e){
			log.info("插入失败");
			e.printStackTrace();
		}
	}

	@Transactional
	public void deleteFromCacheAndDB(String userId,AppNameEnum appName){
		if("-1".equals(userId)) {
			String hxId = appName.getAppName() + userId;
			//写入缓存
			redisClientAdapter.delete(RedisKey.hxUserStatus.key(hxId));
			//写入数据库
			hxUserWriteMapper.deleteByHxId(hxId);
		}else{
			log.info("试图删除admin用户,禁止此操作");
		}
	}

	@Override
	public Response<?> saveAppSendMsgRecord(AppSendMsgRequest appSendMsgRequest) {
		if(appSendMsgRequest==null){
			throw new BusinessException(ErrorEnum.SOA_ERROR_100000);
		}
		HxAppExtMsg record = new HxAppExtMsg();
		record.setContent(appSendMsgRequest.getContent());
		record.setGuestId(appSendMsgRequest.getGuestId().intValue());
		record.setImAgentId(appSendMsgRequest.getImAgentId());
		record.setOs(appSendMsgRequest.getOs());
		hxAppExtMsgWriteMapper.insertSelective(record);
		return ResponseUtil.getResultToResponse(null);
	}
}
